/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package org.rpgmapper.character;

import com.jme3.cinematic.MotionPath;
import com.jme3.cinematic.MotionPathListener;
import com.jme3.cinematic.events.CinematicEvent;
import com.jme3.cinematic.events.CinematicEventListener;
import com.jme3.cinematic.events.MotionEvent;
import com.jme3.cinematic.events.MotionTrack;
import com.jme3.math.FastMath;
import com.jme3.math.Quaternion;
import com.jme3.math.Vector3f;
import com.jme3.scene.Geometry;
import com.jme3.scene.Node;
import com.jme3.scene.shape.Quad;
import com.jme3.util.TempVars;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import org.rpgmapper.JmeMain;
import org.rpgmapper.camera.RTSCameraHandler;
import org.rpgmapper.manager.MapManager;
import org.rpgmapper.manager.CellSelectionChangeListener;
import org.rpgmapper.bo.Character;
import org.rpgmapper.bo.Stat;
import org.rpgmapper.tools.AppContext;

/**
 *
 * @author Nehon
 */
public class CharacterManager implements CinematicEventListener, CellSelectionChangeListener, MotionPathListener {

    private CharacterModel model;
    private int currentCell = 0;
    private int previousCell = 0;
    private boolean diagonal = false;
    private MotionPath path;
    private MotionEvent track;
    private int move = 0;
    private Character character;
    private MapManager mapManager;
    private RTSCameraHandler rtsCam;
    private List<Integer> controlledArea = new ArrayList<Integer>(8);

    public CharacterManager(CharacterModel theModel, Character character) {

        model = theModel;
        model.getNode().setName(character.getId() + "");
        mapManager = AppContext.getMapManager();
        rtsCam = AppContext.getRtsCam();
        float size = 3;//model.getNode().getWorldBound().getVolume()+1;
        //    System.out.println(model.getNode().getWorldBound().getVolume());
        Quad q = new Quad(size, size);
        Geometry shadow = new Geometry(model.getNode().getName() + "-shadow", q);
        shadow.setMaterial(AppContext.getAssetManager().loadMaterial("Materials/Shadow/IndivShadow.j3m"));
        float pos = size / 2f;
        shadow.setLocalTranslation(-pos, 0, pos);
        shadow.setLocalRotation(new Quaternion().fromAngleAxis(-FastMath.HALF_PI, Vector3f.UNIT_X));
        model.getNode().attachChild(shadow);


        TempVars vars = TempVars.get();
        model.getNode().setLocalTranslation(mapManager.getCoordinates(currentCell, vars.vect1));
        rtsCam.lookAt(vars.vect1);
        vars.release();

        this.character = character;
        path = new MotionPath();
        //path.setPathSplineType(SplineType.Linear);
        track = new MotionTrack(model.getNode(), path);
        track.setDirectionType(MotionTrack.Direction.Path);
        //track.setDirectionType(MotionTrack.Direction.PathAndRotation);
        //     track.setRotation(new Quaternion().fromAngleAxis(-FastMath.HALF_PI, Vector3f.UNIT_X));

    }

    public void setCell(int cell) {
        currentCell = cell;
        TempVars vars = TempVars.get();
        model.getNode().setLocalTranslation(mapManager.getCoordinates(currentCell, vars.vect1));
        rtsCam.lookAt(vars.vect1);
        vars.release();
        computeControlledArea(cell);

    }

    private void computeControlledArea(int cell) {
        controlledArea.clear();
        // controlledArea.add(cell);
        cell++;
        controlledArea.add(cell);
        cell -= 2;
        controlledArea.add(cell);
        cell -= mapManager.getGridSize();
        controlledArea.add(cell);
        cell++;
        controlledArea.add(cell);
        cell++;
        controlledArea.add(cell);
        cell += (mapManager.getGridSize() * 2);
        controlledArea.add(cell);
        cell--;
        controlledArea.add(cell);
        cell--;
        controlledArea.add(cell);

//        System.err.println("Controlled area : " + character.getName());
//        for (Integer integer : controlledArea) {
//            System.err.print(integer + ",");
//        }
//        System.err.println();
//        
//        for (Integer area : getControlledArea()) {
//            mapManager.setColor(area, MapManager.CellColor.Character);
//        }
//        mapManager.updateTexture();
    }

    public Node getModel() {
        return model.getNode();
    }

    public void startMove() {

        for (Iterator<CharacterManager> it = mapManager.characterIterator(); it.hasNext();) {
            CharacterManager cm = it.next();
            if ((character.getSide() > 0 && cm.character.getSide() == 0) || (cm.character.getSide() > 0 && character.getSide() == 0)) {
                mapManager.setColorPattern(cm.currentCell, MapManager.CellColor.Aoo, MapManager.Pattern.Controlled, false);
            }
        }

        mapManager.setColorPattern(currentCell, MapManager.CellColor.Move, MapManager.Pattern.valueOf("Move" + character.get(Stat.MovePoints)), true);
        mapManager.setColor(currentCell, MapManager.CellColor.Selected);
        mapManager.updateTexture();
        diagonal = false;
        move = 0;
        previousCell = currentCell;
        path.clearWayPoints();
        path.addWayPoint(model.getNode().getWorldTranslation().clone());

        AppContext.getSelectionManager().addCellListener(this);
    }

    public void doMove() {

        mapManager.clear();
        AppContext.getSelectionManager().removeCellListener(this);

        if (path.getNbWayPoints() > 1) {
            track.setPath(path);
            //   track.setSpeed(2);
            track.setInitialDuration(path.getNbWayPoints() * 0.5f);
            track.play();
            model.walk();
            track.addListener(this);
        } else {
            mapManager.setColor(currentCell, MapManager.CellColor.Selected);

        }
        mapManager.updateTexture();
    }

    public int getCurrentCell() {
        return currentCell;
    }

    @Override
    public void onPlay(CinematicEvent cinematic) {
    }

    @Override
    public void onPause(CinematicEvent cinematic) {
    }

    @Override
    public void onStop(CinematicEvent cinematic) {
        currentCell = previousCell;
        mapManager.setColor(currentCell, MapManager.CellColor.Selected);
        mapManager.updateTexture();
        rtsCam.lookAt(model.getNode().getWorldTranslation());
        model.stop();
        computeControlledArea(currentCell);
        track.removeListener(this);
    }

    public List<Integer> getControlledArea() {
        return controlledArea;
    }

    public void onSelectionChange(int cellNum, Vector3f contactPoint) {
        if (contactPoint != null) {
            //mapManager.clear();
            // mapManager.setColorPattern(cellNum, MapManager.CellColor.Aoo,MapManager.Pattern.Controlled); 

            int gridSize = mapManager.getGridSize();
            boolean moved = false;
            if (move < character.get(Stat.MovePoints)) {
                if (previousCell == cellNum - 1 || previousCell == cellNum + 1 || previousCell == cellNum - gridSize || previousCell == cellNum + gridSize) {
                    move++;
                    moved = true;
                }

                if (previousCell == cellNum - gridSize - 1 || previousCell == cellNum - gridSize + 1 || previousCell == cellNum + gridSize - 1 || previousCell == cellNum + gridSize + 1) {
                    if (!diagonal) {
                        move++;
                        diagonal = true;
                        moved = true;
                    } else {
                        if (move + 2 <= character.get(Stat.MovePoints)) {
                            move += 2;
                            diagonal = false;
                            moved = true;
                        }
                    }
                }
                if (moved) {
                    mapManager.mixColor(cellNum, MapManager.CellColor.Selected);
                    mapManager.updateTexture();

                    path.addWayPoint(mapManager.getCoordinates(cellNum, contactPoint));
                    rtsCam.lookAt(contactPoint);
                    previousCell = cellNum;
                }
            }
        }
    }

    public Character getCharacter() {
        return character;
    }

    public void onWayPointReach(MotionTrack mt, int i) {
    }

    public void onWayPointReach(MotionEvent motionControl, int wayPointIndex) {
        throw new UnsupportedOperationException("Not supported yet.");
    }
}
